module sw.wiki.commentlist;
version(Wiki):
import sw.name, nazo.date, std.string, nazo.savelist, sw.siteconfig, std.conv, sw.utils, nazo.file, std.stdio;

struct Comment{
  string name;
  string message;
  d_time datetime;
  string url;
  string mail;
  string del_md5;
  string page;//AllCommentList Only
  string op;//AllCommentList Only
  uint index;//Remove Only
  void newComment(SiteConfig* cfg,string name,string message,string url,string mail,string del_md5){
    this.name=name;
    this.message=message;
    this.url=url;
    this.mail=mail;
    this.del_md5=del_md5;
    this.datetime=getUTCtime();
  }
}

private T min(T)(T a,T b){
  return a>b?b:a;
}

///FIXME: 高速化
private string encode(string str){
/*  int i=0;
  foreach(c;str)
    if(c=='\\' || c==',' || c=='\n' || c=='\r')i++;
  string rv = new char[i+str.length];
  int b=0, p=0;
  foreach(i,c;str){
    if(c=='\\' || c==',' || c=='\n' || c=='\r'){
      rv[b+p..i+p] = str[b..i];
      rv[i+p] = '\\';
      b = i+1;
      p++;
    }
  }*/

  return str.replace("\\","\\\\").replace(",","\\c").replace("\n","\\n").replace("\r","\\r");
}
///FIXME: 高速化
private string decode(string str){
  return str.replace("\\n","\n").replace("\\r","\r").replace("\\c",",").replace("\\\\","\\");
}

class AllCommentList:TSaveList!("comment.lst"){
  Comment[] getAllComments(uint i){
    Comment[] re=new Comment[length-i];
    foreach(uint i2,string l;this[i..length]){
      toComment(&re[i2],l);
    }
    return re;
  }
  private void toComment(Comment* cmt,string l){
    string[] data=l.split(",");
    cmt.op=data[0];
    cmt.page=decode(data[1]);
    if(cmt.op[0]=='r'){
      cmt.index=.toUint(data[2]);
      return;
    }
    cmt.name=decode(data[2]);
    cmt.message=decode(data[3]);
    cmt.datetime=getUTCtimeFromUtime(.toInt(data[4]));
    cmt.url=decode(data[5]);
    cmt.mail=decode(data[6]);
    cmt.del_md5=decode(data[7]);
  }
  Comment[] getComments(uint i=uint.max){
    uint m=min(length,i);
    Comment[] re=new Comment[m];
    uint n;
    foreach_reverse(string l;this){
      if(n==m)break;
      toComment(&re[n],l);
      if(re[n].op[0]=='r')
        continue;
      n++;
    }
    re.length=n;
    return re;
  }
}

class CommentList:SaveList{
  private:
    string path;
    string name;
    AllCommentList recent;
  public{
    static string getFileName(string name){
      return "dat/"~titleToFileName(name)~".cmt.lst";
    }
    ///コンストラクタ
    this(string name){
      this.name=name;
      path=getFileName(name);
      if(!exists("dat")){
        mkdir("dat");
      }
      recent=new AllCommentList;
      super(path);
    }
    private void toComment(Comment* cmt,string l){
      string[] data=l.split(",");
      cmt.name=decode(data[0]);
      cmt.message=decode(data[1]);
      cmt.datetime=getUTCtimeFromUtime(.toInt(data[2]));
      cmt.url=decode(data[3]);
      cmt.mail=decode(data[4]);
      cmt.del_md5=decode(data[5]);
    }
    Comment[] getComments(){
      Comment[] re=new Comment[length];
      foreach(uint i,string l;this){
        toComment(&re[i],l);
      }
      return re;
    }
    void addComment(Comment* cmt,bool log=true){
      this.append(encode(cmt.name)~","~encode(cmt.message)~","~std.string.toString(toUtime(cmt.datetime))~","~encode(cmt.url)~","~encode(cmt.mail)~","~encode(cmt.del_md5));
      if(log)recent.append("a,"~encode(name)~","~encode(cmt.name)~","~encode(cmt.message)~","~std.string.toString(toUtime(cmt.datetime))~","~encode(cmt.url)~","~encode(cmt.mail)~","~encode(cmt.del_md5));
    }
    Comment* getComment(uint i){
      Comment* cmt=new Comment;
      toComment(cmt,this[i]);
      return cmt;
    }
    void removeComment(uint i,bool log=true){
      string[] l=getList();
      l=l[0..i]~l[i+1..$];
      setList(l);
      if(log)recent.append("r,"~encode(name)~","~std.string.toString(i));
    }
  }
}
